using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Runtime.InteropServices;

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime GetTime()
    {
        //return (SqlDateTime)DateTime.Now;
        return (SqlDateTime)GetNowDt();
    }

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlString GetTimeAsString()
    {
        return (SqlString)(GetNowDt().ToString("O"));
    }

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlInt64 GetFrequency()
    {
        return (SqlInt64)(Int64)GetFreq();
    }

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlInt64 GetTickCount()
    {
        UInt64 i64;
        if (!QueryPerformanceCounter(out i64))
            i64 = 0;
        return (SqlInt64)(Int64)i64;
    }

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlInt64 GetMs()
    {
        return (SqlInt64)(Int64)GetNowI64();
    }

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlInt64 GetTicksPast(Int64 zero)
    {
        UInt64 uiRes = GetNowI64() - (UInt64)zero;
        return (SqlInt64)(Int64)uiRes;
    }

    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlInt64 GetMicrosPast(Int64 zero)
    {
        UInt64 uiRes = GetNowI64() / 10;
        uiRes -= (UInt64)zero;
        return (SqlInt64)(Int64)uiRes;
    }

    #region "Timer routines"
    [DllImport("kernel32.dll")]
    static extern public bool QueryPerformanceCounter(out UInt64 i64);
    [DllImport("kernel32.dll")]
    static extern public bool QueryPerformanceFrequency(out UInt64 i64);
    static protected UInt64 i64Freq = 0;
    public static UInt64 GetNowI64()
    {
        UInt64 i64;
        if (!QueryPerformanceCounter(out i64))
            i64 = 0;
        return (i64 * 10000000) / GetFreq();
    }
    public static UInt64 GetFreq()
    {
        if (0 == i64Freq)
            if (!QueryPerformanceFrequency(out i64Freq))
                i64Freq = 1;
        return i64Freq;
    }
    protected static DateTime dtBaseline = DateTime.MinValue;
    protected static UInt64 i64Baseline = 0;
    public static DateTime GetNowDt()
    {
        UInt64 i64Now = GetNowI64();
        DateTime dt;
        if (dtBaseline == DateTime.MinValue || i64Baseline == 0 || i64Baseline > i64Now)
        { // We have no reference point, or reference point is no longer sufficient: create one.
            dtBaseline = DateTime.Now;
            i64Baseline = i64Now;
            dt = dtBaseline;
        }
        else
        { // We have a sufficient baseline, return baseline plus timespan for diff
            dt = new DateTime(dtBaseline.Ticks + (Int64)(i64Now - i64Baseline));
        }
        return dt;
    }
    #endregion "Timer routines"
};